package com.im.app.utils.uuid;


import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


@Slf4j
public class RSAUtils {

    private static final String PUBLICK_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjxxYz60SbLWmT2SJ3KDPMbFq8" +
            "yLiMhCfbdxG6xaLJI4duB4MpRzMczOewgTuSJuYH4bGX8Ngvt5U9zAC4KzHVueDE" +
            "fx0wUMSZmFu9HMXA1sKingGfkhvgLKB7kLtvchRFkAwSXIPQIPrP9JIRW2HfZgB9" +
            "TimuwgB2lfDzLcBGYQIDAQAB";

    private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKPHFjPrRJstaZPZ" +
            "IncoM8xsWrzIuIyEJ9t3EbrFoskjh24HgylHMxzM57CBO5Im5gfhsZfw2C+3lT3M" +
            "ALgrMdW54MR/HTBQxJmYW70cxcDWwqKeAZ+SG+AsoHuQu29yFEWQDBJcg9Ag+s/0" +
            "khFbYd9mAH1OKa7CAHaV8PMtwEZhAgMBAAECgYAL/DnHuuPeZ0hepXk8NxjzUMqj" +
            "Hh1DSziPevs1K9lp1svGZY5Xqvo2lVgvNoXhgC89TGrur5ViiJDHYPJ8h8yxtTYq" +
            "5V807hl3fiWXBtuAKj68eZ7jUkEf/nKHVsTJ/vcvnBAOp2a4ae0W2lNpLp2kyLAP" +
            "0D2/jnAZjdw+1vQL8QJBAOJEL1HOGCqXzQ6DYDFahogUGl2bDEXMVVQGbmuroTKM" +
            "/LbRyfM/Rj+4XSaSuzc2V1RI8V5zFFUeA972LOwiEA8CQQC5TLlI9AQCZANudTsp" +
            "M8RbH8Lyt3IkkuRUhGQwKFGSGB8KWmDHx6T2GnrzBwyV0hozMW9PSHE1LS1ut3sk" +
            "o9KPAkEA2prx9OFfq9caAMmhKE3D6Lkzd/iS9OSkFBhamqApj8NzbdZmfSNG5c1k" +
            "Ah6FzqQr33zR5mTc4herucCySjnmtQJAQjnwsuk7kZsrOsw9Y8FzuVnFtDfqXLX/" +
            "U1Gp+Sg/1yY12d5pXp21EJxwOvHXBqj74jYV4VEz3NyTs1FyeqrucwJAHZISpjav" +
            "Q3Cwd++nzWWo/64oUzQmMqxt1zrMSN04UlIEUAl7q5Gzg7V2FiWT9Ke+YcVSIcRf" +
            "6HYQBb1zltYnTA==";

    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final int MAX_DECRYPT_BLOCK = 128;
    private static final int MAX_ENCRYPT_BLOCK = 117;
    //加密回的是base64
    public static String encrypt(String data) throws UnsupportedEncodingException {

        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        byte[] decode = decode(PUBLICK_KEY);
        byte[] result = new byte[]{0};
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
                    .generatePublic(new X509EncodedKeySpec(decode));
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int inputLen = dataByte.length;

            int offset = 0;
            byte[] cache;
            int i = 0;
            while (inputLen - offset > 0){
                if (inputLen - offset > MAX_ENCRYPT_BLOCK){
                    cache = cipher.doFinal(dataByte,offset,MAX_ENCRYPT_BLOCK);
                }else {
                    cache = cipher.doFinal(dataByte,offset,inputLen - offset);
                }
                out.write(cache,0,cache.length);
                i++;
                offset = i * MAX_ENCRYPT_BLOCK;
            }
            result = out.toByteArray();
            out.close();
        }
        catch (NoSuchAlgorithmException | InvalidKeyException
               | IllegalBlockSizeException | BadPaddingException
               | NoSuchPaddingException | InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return new String(encode(result));
    }

    //解密
    public static String decrypt(String encrypted){
        byte[] content = decode(encrypted);
        byte[] decoded = decode(PRIVATE_KEY);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {

            RSAPrivateCrtKey priKey = (RSAPrivateCrtKey)KeyFactory.getInstance("RSA")
                    .generatePrivate(new PKCS8EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, priKey);

            int offset = 0;
            byte[] cache;
            int i = 0;

            int inputLen = content.length;
            while (inputLen - offset > 0){
                if (inputLen - offset > MAX_DECRYPT_BLOCK){
                    cache = cipher.doFinal(content,offset,MAX_DECRYPT_BLOCK);
                }else {
                    cache = cipher.doFinal(content,offset,inputLen - offset);
                }
                out.write(cache,0,cache.length);
                i++;
                offset = i * MAX_DECRYPT_BLOCK;
            }
        }
        catch (InvalidKeySpecException | IllegalBlockSizeException
               | BadPaddingException | InvalidKeyException |
               NoSuchPaddingException | NoSuchAlgorithmException e){
            e.printStackTrace();
        }

        return out.toString();
    }

    public static byte[] encode(byte[] txt) throws UnsupportedEncodingException {

        return Base64.getEncoder().encode(txt);
    }

    public static byte[] decode(String txt){
        return Base64.getDecoder().decode(txt);
    }
}


